package com.oceansoft.mobile.econsole.weixin.api.config;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.oceansoft.mobile.econsole.common.spring.SpringContextHolder;
import com.oceansoft.mobile.econsole.common.util.HttpClientUtil;
import com.oceansoft.mobile.econsole.weixin.api.response.GetJsApiTicketResponse;
import com.oceansoft.mobile.econsole.weixin.util.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.io.IOException;
import java.io.Serializable;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * API配置类，项目中请保证其为单例
 *
 * @author peiyu
 * @since 1.2
 */
public final class ApiConfig {

    private static final Logger LOG = LoggerFactory.getLogger(ApiConfig.class);
    public final AtomicBoolean refreshing = new AtomicBoolean(false);
    private final String appid;
    private final String secret;
    private String accessToken;
    private String jsApiTicket;
    private boolean enableJsApi;
    //    private static final String TOKEN_URL = "http://100.101.1.2:8081/web/api/v1/wx/token";
    private static final String API_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
    private static final String URL_JS_API_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";
    //    private static final String TOKEN_URL = "http://gawx.daqing.gov.cn/web/api/v1/wx/token";// 线下操作
    private static final String WECHAT_REDIS_KEY_ACCESS_TOKEN = "wechat:access.token";
    private static final String WECHAT_REDIS_KEY_JS_APITICKET = "wechat:js.api.ticket";
    private String weixin_api_accesstoken = "";
    private String weixin_outh_jsApiTicket = "";

    private static RedisTemplate<Serializable, Object> redisTemplate = SpringContextHolder.getBean("redisTemplate");

    /**
     * 构造方法一，实现同时获取access_token。不启用jsApi
     *
     * @param appid  公众号appid
     * @param secret 公众号secret
     */
    public ApiConfig(String appid, String secret) {
        this(appid, secret, false);
    }

    /**
     * 构造方法二，实现同时获取access_token，启用jsApi
     *
     * @param appid       公众号appid
     * @param secret      公众号secret
     * @param enableJsApi 是否启动js api
     */
    public ApiConfig(String appid, String secret, boolean enableJsApi) {
        this.appid = appid;
        this.secret = secret;
        this.enableJsApi = enableJsApi;
        init();
    }

    public String getAppid() {
        return appid;
    }

    public String getSecret() {
        return secret;
    }

    public String getAccessToken() {
        return getToken();
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public String getJsApiTicket() {
        return getWeChatJsApiTicket();
    }

    public void setJsApiTicket(String jsApiTicket) {
        this.jsApiTicket = jsApiTicket;
    }

    public boolean isEnableJsApi() {
        return enableJsApi;
    }

    public void setEnableJsApi(boolean enableJsApi) {
        this.enableJsApi = enableJsApi;
    }

    /**
     * 初始化微信配置，即第一次获取access_token
     */
    public void init() {
        weixin_api_accesstoken = getWeChatToken();
        accessToken = weixin_api_accesstoken;
        if (enableJsApi) {
            weixin_outh_jsApiTicket = getWeChatJsApiTicket();
            jsApiTicket = weixin_outh_jsApiTicket;
        }
    }

    private String getToken() {
        return getWeChatToken();
    }

    /**
     * 获取指定KEY的值
     *
     * @param key KEY
     * @return String返回值为String类型
     */
    protected String get(final String key) {
        return redisTemplate.execute(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection redisConnection) throws DataAccessException {
                RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
                byte[] _val = redisConnection.get(serializer.serialize(key));
                if (null == _val) {
                    return null;
                }
                return serializer.deserialize(_val);
            }
        });
    }

    /**
     * @param key     缓存KEY
     * @param object  缓存对象
     * @param expires 过期时间(单位为秒)
     */
    protected void cache(final String key, final String object, final long expires) {
        redisTemplate.execute(new RedisCallback<Void>() {
            @Override
            public Void doInRedis(RedisConnection connection) throws DataAccessException {
                RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
                connection.setEx(serializer.serialize(key), expires, serializer.serialize(object));
                return null;
            }
        });
    }

    /**
     * 判断KEY是否存在
     *
     * @param key 返回true表示存在 反之返回false
     * @return boolean
     */
    protected boolean exists(final String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception ex) {
            return false;
        }
    }

    /**
     * 去微信服务器拿Token
     *
     * @return
     */
    public String getWeChatToken() {
        String token = this.get(WECHAT_REDIS_KEY_ACCESS_TOKEN);
        if (Strings.isNullOrEmpty(token)) {
            try {
                String rtToken = HttpClientUtil.doGet(String.format(API_ACCESS_TOKEN, appid, secret));
                JSONObject rtObj = JSONObject.parseObject(rtToken);
                token = rtObj.getString("access_token");
                cache(WECHAT_REDIS_KEY_ACCESS_TOKEN, token, 7000);
            } catch (IOException e) {
                LOG.error("获取access_token失败");
            }
        }
        return token;
    }

    /**
     * 去微信服务器拿 JsApiTicket
     *
     * @return
     */
    public String getWeChatJsApiTicket() {

        String apiTicket = this.get(WECHAT_REDIS_KEY_JS_APITICKET);
        if (Strings.isNullOrEmpty(apiTicket)) {
            try {
                String rtToken = HttpClientUtil.doGet(String.format(URL_JS_API_TICKET, getWeChatToken()));
                GetJsApiTicketResponse response = JSONUtil.toBean(rtToken, GetJsApiTicketResponse.class);
                apiTicket = response.getTicket();
                cache(WECHAT_REDIS_KEY_JS_APITICKET, apiTicket, 7000);
            } catch (IOException e) {
                LOG.error("获取JsApiTicket失败");
            }
        }
        return apiTicket;
    }

}
